package com.spring.framework.config.value;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.stereotype.Component;

/**
 * 我们使用@PropertySource注解加载单个配置文件，如果有多个配置文件，那么可以使用@PropertySources加载多个配置文件，如果多个配置文件中有相同的key，那么后
 * 加载的配置文件将覆盖之前加载的配置文件的value值。先后加载的顺序就是声明加载的顺序，先声明的先加载。也可以就使用@PropertySource，填写多个文件参数，使用,
 * 分隔。另外，加载进来的配置全局通用，其他的bean也可以直接使用不需要再加载了。因此，实际上配置文件常常在@Configuration配置类中加载，而不是普通的bean中加载。
 * <p>
 * Spring默认情况下，如果配置文件没有key，则将${key}本身将尝试作为值注入，如果注入成功（比如属性是String类型则肯定能注入成功）则不会抛出异常。
 * <p>
 * 如果我们需要启动检查没有的key，要对不存在的值保持严格控制，让它抛出异常，我们可以向IoC容器注册一个PropertySourcesPlaceholderConfigurer对象！
 * <p>
 * 通常我们使用@Bean方式将PropertySourcesPlaceholderConfigurer注册到IoC容器中，并且要求对应的方法是static方法。在Spring Boot中，默认情况下，会有一个
 * PropertySourcesPlaceholderConfigurer被初始化，自动从application.properties and application.yml中加载配置。
 * <p>
 * 另外，可以重写PropertySourcesPlaceholderConfigurer的setPlaceholderPrefix、setPlaceholderSuffix、setValueSeparator方法来配置我们自己的占位符和
 * 解析。默认占位符实际上就是“${”、“}”等符号，Spring通过解析前置、后置占位符来获取key的信息，或者对里面的值进行拆分。
 * <p>
 * 在此前基于XML的配置中，我们使用property-placeholder来引入外部的配置文件，然后就可以在XML文件或者类中使用同样的语法获取配置文件的信息。比如，引入前面的配
 * 置文件：< context:property-placeholder location=“classpath:value.properties,value3.properties” />。
 * <p>
 * 由于基于XML的配置就是使用的PropertySourcesPlaceholderConfigurer。因此基于XML的配置和Spring Boot项目一样，如果没有对应的key都会直接启动报错！
 *
 * @author xuweizhi
 * @since 2020/12/15 14:45
 */
@Component
//使用@PropertySources
@SuppressWarnings("all")
@PropertySources(value = {
		//value3.properties在后面，因此value3将会覆盖value的同名key的值
		@PropertySource(value = "classpath:config/value.properties", encoding = "UTF-8"),
		@PropertySource(value = "classpath:config/value3.properties", encoding = "UTF-8")
})
//也可以就使用@PropertySource，同样按照定义顺序加载配置文件
//@PropertySource(value = {"classpath:value3.properties", "classpath:value.properties"})
public class ValuePropertiesCheck {

	@Value("${key}")
	private String value;

	//Spring默认情况下，如果配置文件没有对应的key，则将${key}本身将尝试作为值注入
	@Value("${zzz}")
	private String zzz;


	@Override
	public String toString() {
		return "ValuePropertiesCheck{" +
				"value='" + value + '\'' +
				", zzz='" + zzz + '\'' +
				'}';
	}

	/**
	 * 添加一个PropertySourcesPlaceholderConfigurer，将会在启动时检查配置文件没有对应的key的情况，并且抛出异常
	 * 一定要static修饰的方法，在一开始就执行！
	 */
	@Bean
	public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ValuePropertiesCheck.class);
		System.out.println(applicationContext.getBean(ValuePropertiesCheck.class));
	}
}
